package incremental

import (
	"fmt"
	"sync"
	"time"

	"gorm.io/gorm"
)

// BatchProcessor 批量变更处理器
type BatchProcessor struct {
	computer *Computer      // 增量计算引擎
	db       *gorm.DB       // 数据库连接
	changes  chan *Change   // 变更队列（使用channel代替slice）
	mutex    sync.Mutex     // 互斥锁
	wg       sync.WaitGroup // 等待组
	quit     chan struct{}  // 退出信号
	workers  int            // 工作协程数量
	working  chan bool      // 标记是否有工作正在进行
}

// NewBatchProcessor 创建批量变更处理器实例
func NewBatchProcessor(db *gorm.DB, computer *Computer) *BatchProcessor {
	processor := &BatchProcessor{
		computer: computer,
		db:       db,
		changes:  make(chan *Change, 1000), // 缓冲通道，容量1000
		quit:     make(chan struct{}),
		working:  make(chan bool, 1),       // 用于标记是否有工作正在进行
		workers:  3,                        // 默认3个工作协程
	}

	// 初始化working状态
	processor.working <- false

	// 启动工作协程
	for i := 0; i < processor.workers; i++ {
		processor.wg.Add(1)
		go processor.worker()
	}

	return processor
}

// AddChange 添加变更到处理队列
func (bp *BatchProcessor) AddChange(change *Change) error {
	select {
	case bp.changes <- change:
		// 成功添加到队列
		bp.mutex.Lock()
		// 标记正在工作中
		select {
		case <-bp.working:
		default:
		}
		bp.working <- true
		bp.mutex.Unlock()
	case <-bp.quit:
		// 处理器已关闭
		return fmt.Errorf("processor is closed")
	}
	return nil
}

// worker 工作协程，处理变更队列中的变更
func (bp *BatchProcessor) worker() {
	defer bp.wg.Done()

	for {
		select {
		case change := <-bp.changes:
			// 处理单个变更
			bp.processChange(change)
			
			// 如果队列为空，更新工作状态
			if len(bp.changes) == 0 {
				bp.mutex.Lock()
				select {
				case <-bp.working:
				default:
				}
				bp.working <- false
				bp.mutex.Unlock()
			}
		case <-bp.quit:
			// 处理剩余的变更
			for {
				select {
				case change := <-bp.changes:
					bp.processChange(change)
				default:
					// 队列已空，退出
					bp.mutex.Lock()
					select {
					case <-bp.working:
					default:
					}
					bp.working <- false
					bp.mutex.Unlock()
					return
				}
			}
		}
	}
}

// processChange 处理单个变更
func (bp *BatchProcessor) processChange(change *Change) error {
	// 将单个变更包装成切片进行处理
	changes := []*Change{change}

	// 使用计算引擎处理变更
	resultChanges, err := bp.computer.ProcessChanges(changes)
	if err != nil {
		// 错误处理 - 记录日志
		fmt.Printf("处理变更时出错: %v\n", err)
		return err
	}

	// 记录处理成功的日志
	fmt.Printf("成功处理了 %d 个变更，生成了 %d 个新变更\n", len(changes), len(resultChanges))

	return nil
}

// Wait 等待所有当前变更处理完成，但不关闭处理器
func (bp *BatchProcessor) Wait() {
	// 轮询检查是否还有工作正在进行
	for {
		bp.mutex.Lock()
		select {
		case working := <-bp.working:
			if !working && len(bp.changes) == 0 {
				// 没有工作正在进行且队列为空
				bp.working <- false
				bp.mutex.Unlock()
				return
			}
			bp.working <- working
		default:
			// 通道为空，检查队列长度
			if len(bp.changes) == 0 {
				bp.working <- false
				bp.mutex.Unlock()
				return
			}
			bp.working <- true
		}
		bp.mutex.Unlock()
		
		// 等待一小段时间再检查
		time.Sleep(10 * time.Millisecond)
	}
}

// Close 完全关闭处理器，等待所有变更处理完成并释放资源
func (bp *BatchProcessor) Close() {
	close(bp.quit) // 发送退出信号
	bp.wg.Wait()
	close(bp.changes) // 关闭变更队列
}